package com.wlf.util;

import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.parser.ContentByteUtils;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfContentStreamProcessor;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author lingfeng.wei
 * @date 2022/1/7 14:12
 */
public class PdfUtils {

    /**
     * findKeywordPostions
     * @param pdfData     通过IO流 PDF文件转化的byte数组
     * @param keyword     关键字
     * @return List<float [ ]> : float[0]:pageNum float[1]:x float[2]:y
     * @throws IOException
     */
    public static List<float[]> findKeywordPostions(byte[] pdfData, String keyword) throws IOException {
        List<float[]> result = new ArrayList<>();
        List<PdfPageContentPositions> pdfPageContentPositions = getPdfContentPostionsList(pdfData);


        for (PdfPageContentPositions pdfPageContentPosition : pdfPageContentPositions) {
            List<float[]> charPositions = findPositions(keyword, pdfPageContentPosition);
            if (charPositions == null || charPositions.size() < 1) {
                continue;
            }
            result.addAll(charPositions);
        }
        return result;
    }

    private static List<PdfPageContentPositions> getPdfContentPostionsList(byte[] pdfData) throws IOException {
        PdfReader reader = new PdfReader(pdfData);


        List<PdfPageContentPositions> result = new ArrayList<>();


        int pages = reader.getNumberOfPages();
        for (int pageNum = 1; pageNum <= pages; pageNum++) {
            float width = reader.getPageSize(pageNum).getWidth();
            float height = reader.getPageSize(pageNum).getHeight();


            PdfRenderListener pdfRenderListener = new PdfRenderListener(pageNum, width, height);


            //解析pdf，定位位置
            PdfContentStreamProcessor processor = new PdfContentStreamProcessor(pdfRenderListener);
            PdfDictionary pageDic = reader.getPageN(pageNum);
            PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES);
            try {
                processor.processContent(ContentByteUtils.getContentBytesForPage(reader, pageNum), resourcesDic);
            } catch (IOException e) {
                reader.close();
                throw e;
            }


            String content = pdfRenderListener.getContent();
            List<CharPosition> charPositions = pdfRenderListener.getcharPositions();


            List<float[]> positionsList = new ArrayList<>();
            for (CharPosition charPosition : charPositions) {
                float[] positions = new float[]{charPosition.getPageNum(), charPosition.getX(), charPosition.getY()};
                positionsList.add(positions);
            }


            PdfPageContentPositions pdfPageContentPositions = new PdfPageContentPositions();
            pdfPageContentPositions.setContent(content);
            pdfPageContentPositions.setPostions(positionsList);


            result.add(pdfPageContentPositions);
        }
        reader.close();
        return result;
    }

    private static List<float[]> findPositions(String keyword, PdfPageContentPositions pdfPageContentPositions) {


        List<float[]> result = new ArrayList<>();


        String content = pdfPageContentPositions.getContent();
        List<float[]> charPositions = pdfPageContentPositions.getPositions();


        for (int pos = 0; pos < content.length(); ) {
            int positionIndex = content.indexOf(keyword, pos);
            if (positionIndex == -1) {
                break;
            }
            float[] postions = charPositions.get(positionIndex);
            result.add(postions);
            pos = positionIndex + 1;
        }
        return result;
    }

    private static class PdfPageContentPositions {
        private String content;
        private List<float[]> positions;


        public String getContent() {
            return content;
        }


        public void setContent(String content) {
            this.content = content;
        }


        public List<float[]> getPositions() {
            return positions;
        }


        public void setPostions(List<float[]> positions) {
            this.positions = positions;
        }
    }

    private static class PdfRenderListener implements RenderListener {
        private int pageNum;
        private float pageWidth;
        private float pageHeight;
        private StringBuilder contentBuilder = new StringBuilder();
        private List<CharPosition> charPositions = new ArrayList<>();


        public PdfRenderListener(int pageNum, float pageWidth, float pageHeight) {
            this.pageNum = pageNum;
            this.pageWidth = pageWidth;
            this.pageHeight = pageHeight;
        }


        public void beginTextBlock() {
        }


        public void renderText(TextRenderInfo renderInfo) {
            List<TextRenderInfo> characterRenderInfos = renderInfo.getCharacterRenderInfos();
            for (TextRenderInfo textRenderInfo : characterRenderInfos) {
                String word = textRenderInfo.getText();
                if (word.length() > 1) {
                    word = word.substring(word.length() - 1, word.length());
                }
                Rectangle2D.Float rectangle = textRenderInfo.getAscentLine().getBoundingRectange();

//                float x = (float)rectangle.getX();
                float y = (float)rectangle.getY();
                float x = (float)rectangle.getCenterX();
//                float y = (float)rectangle.getCenterY();
//                double x = rectangle.getMinX();
//                double y = rectangle.getMaxY();

                //这两个是关键字在所在页面的XY轴的百分比
                float xPercent = Math.round(x / pageWidth * 10000) / 10000f;
                float yPercent = Math.round((1 - y / pageHeight) * 10000) / 10000f;
                CharPosition charPosition = new CharPosition(pageNum, (float)x, (float)y);
                charPositions.add(charPosition);
                contentBuilder.append(word);
            }
        }


        public void endTextBlock() {
        }


        public void renderImage(ImageRenderInfo renderInfo) {
        }


        public String getContent() {
            return contentBuilder.toString();
        }


        public List<CharPosition> getcharPositions() {
            return charPositions;
        }
    }
    private static class CharPosition {
        private int pageNum = 0;
        private float x = 0;
        private float y = 0;


        public CharPosition(int pageNum, float x, float y) {
            this.pageNum = pageNum;
            this.x = x;
            this.y = y;
        }


        public int getPageNum() {
            return pageNum;
        }


        public float getX() {
            return x;
        }


        public float getY() {
            return y;
        }


        @Override
        public String toString() {
            return "[pageNum=" + this.pageNum + ",x=" + this.x + ",y=" + this.y + "]";
        }
    }

    public static class PdfItextModel {

        private Float xCoordinate;

        private Float yCoordinate;

        private Integer pageNum;

        private String content;

        public Float getxCoordinate() {
            return xCoordinate;
        }

        public void setxCoordinate(Float xCoordinate) {
            this.xCoordinate = xCoordinate;
        }

        public Float getyCoordinate() {
            return yCoordinate;
        }

        public void setyCoordinate(Float yCoordinate) {
            this.yCoordinate = yCoordinate;
        }

        public Integer getPageNum() {
            return pageNum;
        }

        public void setPageNum(Integer pageNum) {
            this.pageNum = pageNum;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

        public PdfItextModel(Float xCoordinate, Float yCoordinate, Integer pageNum, String content) {
            this.xCoordinate = xCoordinate;
            this.yCoordinate = yCoordinate;
            this.pageNum = pageNum;
            this.content = content;
        }
    }
    // 获取基础文字
    public static BaseFont getBaseFont() throws DocumentException, IOException {
        BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
        return base;
    }

    /**
     *
     * @param oldPswFilePath 原来的文件地址
     * @param list 需要添加的详细信息
     * @return
     * @throws IOException
     * @throws DocumentException
     */
    public static String signSinglePsw(String oldPswFilePath, List<PdfItextModel> list,byte[] pdfData) throws IOException, DocumentException {

        int lastIndex = oldPswFilePath.lastIndexOf('.');
        // 获取文件后缀
        String suffix = oldPswFilePath.substring(lastIndex + 1);
        // 判断是否为pdf文件
        if (!"pdf".equals(suffix.toLowerCase())) {
            throw new RuntimeException("Not is PDF file");
        }

        // 生成新的文件路径
        //String newPswPath = oldPswFilePath.substring(0, lastIndex) + "-副本." + suffix;
        System.out.println("单个psw文件签名生成的新路径：" + oldPswFilePath);

        //解析文件
        PdfReader reader = new PdfReader(pdfData);
        FileOutputStream fOut = new FileOutputStream(oldPswFilePath);
        PdfStamper stp = new PdfStamper(reader, fOut);

        // 总页数
        System.out.println("PDF总页数：" + reader.getNumberOfPages());

        for (PdfItextModel model : list) {
            Float xCoordinate = model.getxCoordinate();
            Float yCoordinate = model.getyCoordinate();
            Integer pageNum = model.getPageNum();
            String content = model.getContent();
            if(xCoordinate == null || yCoordinate == null ||
                    pageNum == null || pageNum == 0 || content == null || "".equals(content)){
                continue;
            }
            PdfContentByte pdfContentByte = stp.getOverContent(pageNum);
            pdfContentByte.beginText();
            // 设置字体及字号
            pdfContentByte.setFontAndSize(getBaseFont(), 16);
            addDeptReview(xCoordinate,yCoordinate,pdfContentByte, content);
            pdfContentByte.endText();
        }
        stp.close();
        // 将输出流关闭
        fOut.close();
        reader.close();
        // 文件读写结束
        System.out.println("PSW文件读写完毕");

        return oldPswFilePath;
    }

    /**
     *
     * @param oldPswFilePath 原来的文件地址
     * @param list 需要添加的详细信息
     * @return
     * @throws IOException
     * @throws DocumentException
     */
    public static void res(OutputStream out, List<PdfItextModel> list, byte[] pdfData) throws IOException, DocumentException {

        //解析文件
        PdfReader reader = new PdfReader(pdfData);
        PdfStamper stp = new PdfStamper(reader, out);

        // 总页数
        System.out.println("PDF总页数：" + reader.getNumberOfPages());

        for (PdfItextModel model : list) {
            Float xCoordinate = model.getxCoordinate();
            Float yCoordinate = model.getyCoordinate();
            Integer pageNum = model.getPageNum();
            String content = model.getContent();
            if(xCoordinate == null || yCoordinate == null ||
                    pageNum == null || pageNum == 0 || content == null || "".equals(content)){
                continue;
            }
            PdfContentByte pdfContentByte = stp.getOverContent(pageNum);
            pdfContentByte.beginText();
            // 设置字体及字号
            pdfContentByte.setFontAndSize(getBaseFont(), 16);
            addDeptReview(xCoordinate,yCoordinate,pdfContentByte, content);
            pdfContentByte.endText();
        }
        stp.close();
        // 将输出流关闭
        out.close();
        reader.close();
        // 文件读写结束
        System.out.println("PSW文件读写完毕");

    }

    /**
     *
     * @param oldPswFilePath 原来的文件地址
     * @param list 需要添加的详细信息
     * @return
     * @throws IOException
     * @throws DocumentException
     */
    public static void responseFile(File tempFile, List<PdfItextModel> list,byte[] pdfData) throws IOException, DocumentException {


        //解析文件
        PdfReader reader = new PdfReader(pdfData);
        FileOutputStream fOut = new FileOutputStream(tempFile);
        PdfStamper stp = new PdfStamper(reader, fOut);

        // 总页数
        System.out.println("PDF总页数：" + reader.getNumberOfPages());

        for (PdfItextModel model : list) {
            Float xCoordinate = model.getxCoordinate();
            Float yCoordinate = model.getyCoordinate();
            Integer pageNum = model.getPageNum();
            String content = model.getContent();
            if(xCoordinate == null || yCoordinate == null ||
                    pageNum == null || pageNum == 0 || content == null || "".equals(content)){
                continue;
            }
            PdfContentByte pdfContentByte = stp.getOverContent(pageNum);
            pdfContentByte.beginText();
            // 设置字体及字号
            pdfContentByte.setFontAndSize(getBaseFont(), 16);
            addDeptReview(xCoordinate,yCoordinate,pdfContentByte, content);
            pdfContentByte.endText();
        }
        stp.close();
        // 将输出流关闭
        fOut.close();
        reader.close();
        // 文件读写结束
        System.out.println("PSW文件读写完毕");

    }

    /**
     * @Author
     * @Date 18:48 2020/3/7
     * @Description 添加水印
     * @param content
     * @param keyword
     * @param x X轴坐标
     * @param y Y轴坐标
     */
    private static void addDeptReview(float x, float y, PdfContentByte content, String keyword) {
        content.setColorFill(BaseColor.BLACK);
        // 设置水印位置和内容
        System.out.println("水印内容：" + keyword);
        System.out.println("打印位置坐标：" + x + "," + y);
        content.showTextAligned(Element.ALIGN_LEFT, keyword, x, y, 0);
    }

    /**
     * 获取文件字节流
     * @param file
     * @return
     */
    public static  byte [] fileBytes(File file){
        //2.定义一个byte数组，长度为文件的长度
        byte[] by = new byte[(int) file.length()];

        //3.IO流读取文件内容到byte数组
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            inputStream.read(by);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                }
            }
        }
        return by;
    }

    public static void main(String[] args) throws Exception {
        //1.给定文件
        File pdfFile = new File("E:/wei/资料/test.pdf");
        //2.定义一个byte数组，长度为文件的长度
        byte[] pdfData = new byte[(int) pdfFile.length()];

        //3.IO流读取文件内容到byte数组
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(pdfFile);
            inputStream.read(pdfData);
        } catch (IOException e) {
            throw e;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                }
            }
        }

        //4.指定关键字
        String keyWord = "用户（盖章/及或签字）";

        //5.调用方法，给定关键字和文件
        List<float[]> positions = findKeywordPostions(pdfData, keyWord);

        //6.返回值类型是  List<float[]> 每个list元素代表一个匹配的位置，分别为 float[0]所在页码  float[1]所在x轴 float[2]所在y轴
        System.out.println("total:" + positions.size());
        if (positions != null && positions.size() > 0) {
            for (float[] position : positions) {
                System.out.print("pageNum: " + (int) position[0]);
                System.out.print("\tx: " + position[1]);
                System.out.println("\ty: " + position[2]);
            }
            float [] pos = positions.get(positions.size()-1);
            System.out.println("-------------开始时间："+new Date());
            List<PdfItextModel> list = new ArrayList<>();
            System.out.println("正在第"+(int) pos[0]+" 页增加签名，坐标 X:"+pos[1]+" Y:"+(pos[2]-40f));
            list.add(new PdfItextModel(pos[1],(pos[2]-45f),(int) pos[0],"高文庆"));
            String filePath = "E:/wei/资料/test.pdf";
            String oldPswFilePath="E:/wei/资料/test-副本.pdf";
            signSinglePsw(oldPswFilePath,list,pdfData);
            System.out.println("------------结束时间："+new Date());
        }
    }

}
